/* SBDETECT.C */ /* Copyright 1997 by Ethan Brodsky. All Rights Reserved. */ /* 97/6/30 - ebrodsky@pobox.com - http://www.pobox.com/~ebrodsky/ */ #include <conio.h> #include <dos.h> #include <stdio.h> #include <stdlib.h> unsigned char read_dsp(int baseio) { while (!(inp(baseio+0x00E) & 0x80)) { } return(inp(baseio+0x00A)); } void write_dsp(int baseio, unsigned char value) { while ((inp(baseio+0x00C) & 0x80)) { } outp(baseio+0x00C, value); } int reset_dsp(int baseio) { unsigned i; outp(baseio+0x006, 1); delay(1); outp(baseio+0x006, 0); for (i = 65535U; i > 0; i--) { if ((inp(baseio+0x00E) & 0x80) && (inp(baseio+0x00A) == 0xAA)) break; } return(i > 0); } ////////////////////////////////////////////////////////////////////////////// int detect_baseio(void) { // list of possible addresses, plus "sentinel" -1 static int val[] = {0x210, 0x220, 0x230, 0x240, 0x250, 0x260, 0x280, -1}; static int count = sizeof(val)/sizeof(*val) - 1; // don't test -1 int i; // for each possible port for (i = 0; i < count; i++) // test it by attempting to reset the DSP if (reset_dsp(val[i])) // if found, break now break; // base io address, or, if not found, -1, since i=count+1 return val[i]; } ////////////////////////////////////////////////////////////////////////////// void dsp_stopall(int baseio) { // pause 8/16-bit DMA mode digitized sound I/O reset_dsp(baseio); write_dsp(baseio, 0xD0); write_dsp(baseio, 0xD5); } unsigned char dma_req(void) // returns dma_request for all channels (bit7->dma7..bit0->dma0) { return (inp(0xD0) & 0xF0) | (inp(0x08) >> 4); } int bitcount(unsigned char x) // returns number of set bits in byte x { int i; int count = 0; for (i = 0; i < 8; i++) if (x & (1 << i)) count++; return count; } int bitpos(unsigned char x) // returns position lowest set bit in byte x (if none, returns -1) { int i; for (i = 0; i < 8; i++) if (x & (1 << i)) return i; return -1; } int find_dma(int baseio, int dmac) { // dma channels active when sound is not: can't be audio DMA channel int dma_maskout = ~0x10; // initially mask only DMA4 (cascade) // dma channels active during audio, minus those masked out int dma_mask = 0; int i; // stop all dsp activity dsp_stopall(baseio); // poll to find out which DMA channels are in use without sound for (i = 0; i < 100; i++) dma_maskout &= ~dma_req(); // now program card and see what channel becomes active if (dmac == 1) { // 8-bit single-cycle DMA mode digitized sound output write_dsp(baseio, 0x14); write_dsp(baseio, 0x00); // lo one sample write_dsp(baseio, 0x00); // hi } else { // 16-bit single-cycle DMA mode digitized sound output write_dsp(baseio, 0xB0); // 16-bit, D/A, S/C, FIFO off write_dsp(baseio, 0x10); // 16-bit mono signed PCM write_dsp(baseio, 0x00); // lo one sample write_dsp(baseio, 0x00); // hi } // poll to find out which (unmasked) DMA channels are in use with sound for (i = 0; i < 100; i++) dma_mask |= dma_req() & dma_maskout; // stop all dsp activity dsp_stopall(baseio); if (bitcount(dma_mask) == 1) return bitpos(dma_mask); else return -1; } int detect_dma(int baseio) { return find_dma(baseio, 1); } int detect_dma16(int baseio) { return find_dma(baseio, 2); } ////////////////////////////////////////////////////////////////////////////// void dsp_transfer(int baseio, int dma8) { static int dma_pageports[] = {0x87, 0x83, 0x81, 0x82, -1, 0x8B, 0x89, 0x8A}; int dma_maskport = 0x0A; int dma_modeport = 0x0B; int dma_clrptrport = 0x0C; int dma_addrport = 0x00+2*dma8; int dma_countport = 0x01+2*dma8; int dma_pageport = dma_pageports[dma8]; // mask DMA channel outp(dma_maskport, 0x04 | dma8); // write DMA mode: single-cycle read transfer outp(dma_modeport, 0x48 | dma8); // clear byte-pointer flip-flop outp(dma_clrptrport, 0x00); // one transfer outp(dma_countport, 0x00); // lo outp(dma_countport, 0x00); // hi // address ???????? outp(dma_addrport, 0); // lo outp(dma_addrport, 0); // hi outp(dma_pageport, 0); // unmask DMA channel outp(dma_maskport, 0x00 | dma8); // 8-bit single-cycle DMA mode digitized sound output write_dsp(baseio, 0x14); write_dsp(baseio, 0x00); // lo one sample write_dsp(baseio, 0x00); // hi } static void ((interrupt far *old_handler[16])(void)); static int irq_hit[16]; static int irq_mask[16]; void clear_irq_hit(void) { int i; for (i = 0; i < 16; i++) irq_hit[i] = 0; } void interrupt irq2_handler(void) { irq_hit[2] = 1; _chain_intr(old_handler[2]); } void interrupt irq3_handler(void) { irq_hit[3] = 1; _chain_intr(old_handler[3]); } void interrupt irq5_handler(void) { irq_hit[5] = 1; _chain_intr(old_handler[5]); } void interrupt irq7_handler(void) { irq_hit[7] = 1; _chain_intr(old_handler[7]); } void interrupt irq10_handler(void) { irq_hit[10] = 1; _chain_intr(old_handler[10]); } int detect_irq(int baseio, int dma8) { int pic1_oldmask, pic2_oldmask; int irq = -1; int i; // install handlers old_handler[2] = _dos_getvect(0x0A); _dos_setvect(0x0A, irq2_handler); old_handler[3] = _dos_getvect(0x0B); _dos_setvect(0x0B, irq3_handler); old_handler[5] = _dos_getvect(0x0D); _dos_setvect(0x0D, irq5_handler); old_handler[7] = _dos_getvect(0x0F); _dos_setvect(0x0F, irq7_handler); old_handler[10] = _dos_getvect(0x72); _dos_setvect(0x72, irq10_handler); // save old IRQ mask and unmask IRQs pic1_oldmask = inp(0x21); outp(0x21, pic1_oldmask & 0x53); pic2_oldmask = inp(0xA1); outp(0xA1, pic2_oldmask & 0xFB); clear_irq_hit(); // wait to see what interrupts are triggered without sound delay(100); // mask out any interrupts triggered without sound for (i = 0; i < 16; i++) irq_mask[i] = irq_hit[i]; clear_irq_hit(); // try to trigger an interrupt using DSP command F2 write_dsp(baseio, 0xF2); delay(10); // detect any interrupts triggered for (i = 0; i < 16; i++) if (irq_hit[i] && !irq_mask[i]) irq = i; // if F2 fails to trigger an interrupt, run a short transfer if (irq == -1) { reset_dsp(baseio); dsp_transfer(baseio, dma8); delay(10); // detect any interrupts triggered for (i = 0; i < 16; i++) if (irq_hit[i] && !irq_mask[i]) irq = i; } // reset DSP in case we've confused it reset_dsp(baseio); // remask IRQs outp(0x21, pic1_oldmask); outp(0xA1, pic2_oldmask); // uninstall handlers _dos_setvect(0x0A, old_handler[2]); _dos_setvect(0x0B, old_handler[3]); _dos_setvect(0x0D, old_handler[5]); _dos_setvect(0x0F, old_handler[7]); _dos_setvect(0x72, old_handler[10]); return irq; } ////////////////////////////////////////////////////////////////////////////// int sb_detect(int *baseio, int *irq, int *dma, int *dma16) { *irq = -1; *dma16 = -1; if ((*baseio = detect_baseio()) == -1) return 0; if ((*dma = detect_dma(*baseio)) == -1) return 0; if ((*dma16 = detect_dma16(*baseio)) == -1) return 0; if ((*irq = detect_irq(*baseio, *dma)) == -1) return 0; return 1; } int main() { int baseio, irq, dma, dma16; int detected; detected = sb_detect(&baseio, &irq, &dma, &dma16); printf("%s \n", detected ? "Success" : "Failure"); printf("baseio: %Xh \n", baseio); printf("irq: %i \n", irq); printf("dma: %i \n", dma); printf("dma16: %i \n", dma16); return !detected; }